--- title: "02-Java 对象的创建与引用" aliases: - "Java 对象的创建与引用" created: 2025-12-24 --- # Java 对象的创建与引用 ## **一、使用 new 运算符创建对象** ### **1.1 基本语法** ``` 类名 引用变量 = new 类名(构造参数); // 示例 Student stu = new Student("张三", 20); ``` ### **1.2 创建过程分解** ```drawio ``` ### **1.3 详细执行步骤** | **步骤** | **操作** | **说明** | | --- | --- | --- | | ① | 加载类 | 如果 Student 类未加载,先加载到方法区 | | ② | 分配内存 | 在堆中为新对象分配内存空间 | | ③ | 默认初始化 | 属性赋默认值(0/null/false) | | ④ | 显式初始化 | 执行属性声明时的赋值 | | ⑤ | 构造方法 | 执行构造方法中的代码 | | ⑥ | 返回地址 | 将对象内存地址赋给引用变量 | ### **1.4 代码示例:观察初始化顺序** ```java public class Student { // ② 显式初始化 private String name = "默认姓名"; private int age = 0; // ③ 构造方法 public Student(String name, int age) { System.out.println("构造前 name = " + this.name); // 输出:默认姓名 this.name = name; this.age = age; System.out.println("构造后 name = " + this.name); // 输出:张三 } public static void main(String[] args) { Student stu = new Student("张三", 20); } } ``` **输出**结果: ``` 构造前 name = 默认姓名 构造后 name = 张三 ``` ## **二、堆内存与栈内存** ### **2.1 JVM 内存结构概览** ```drawio ``` ### **2.2 栈内存 vs 堆内存 对比表** | **特性** | **栈内存 (Stack)** | **堆内存 (Heap)** | | --- | --- | --- | | **存储内容** | 局部变量、方法参数、引用地址 | 对象实例、数组 | | **生命周期** | 方法执行期间 | 直到无引用被 GC 回收 | | **分配速度** | 快(指针移动) | 慢(需找空闲空间) | | **空间大小** | 较小(默认 1MB) | 较大(可配置 GB 级) | | **线程关系** | 线程私有 | 线程共享 | | **内存管理** | 自动释放 | 垃圾回收器管理 | | **溢出异常** | StackOverflowError | OutOfMemoryError | --- ### **2.3 代码示例:理解内存分配** ```java public class MemoryDemo { public static void main(String[] args) { // 基本类型 → 值存在栈中 int num = 100; // 引用类型 → 引用在栈中,对象在堆中 Student stu = new Student("张三", 20); // 数组也是对象 → 堆中 int[] arr = new int[]{1, 2, 3}; // 调用方法 process(stu); } public static void process(Student s) { // s 是新的引用,指向同一个对象 String name = s.getName(); // name 引用在栈中 } } ``` **内存图解**: ```drawio ``` ## **三、对象实体与对象引用** ### **3.1 核心概念** ```drawio ``` ### **3.2 气球与绳子类比** ```drawio ``` ### **3.3 代码验证** ```java public class ReferenceDemo { public static void main(String[] args) { // 规则 1:绳子可以不系气球 Student stu1 = null; // stu1.getName(); // ❌ NullPointerException // 规则 2:绳子只能系一个气球 Student stu2 = new Student("张三", 20); System.out.println(stu2.getName()); // 张三 stu2 = new Student("李四", 21); // stu2 改系新气球 System.out.println(stu2.getName()); // 李四 // "张三"对象无人引用,等待 GC 回收 // 规则 3:多条绳子系同一个气球 Student s1 = new Student("王五", 22); Student s2 = s1; // s2 系上 s1 的气球 Student s3 = s1; // s3 也系上同一个气球 // 验证:修改一处,全部生效 s2.setAge(30); System.out.println(s1.getAge()); // 30 System.out.println(s3.getAge()); // 30 } } ``` ## **四、引用相等 vs 对象相等** ### **4.1 概念对比** ```drawio ``` ### **4.2 代码示例** ```java public class EqualityDemo { public static void main(String[] args) { Student s1 = new Student("张三", 20); // 对象 A Student s2 = s1; // 也指向对象 A Student s3 = new Student("张三", 20); // 对象 B(内容相同) // ====== 引用相等(==):比较地址 ====== System.out.println(s1 == s2); // true (同一对象) System.out.println(s1 == s3); // false (不同对象) // ====== 对象相等(equals):比较内容 ====== // 注意:需要 Student 类重写 equals 方法才能正确比较 System.out.println(s1.equals(s3)); // 取决于 equals 实现 } } ``` **内存示意图**: ```drawio ``` ## **五、== 与 equals() 详解** ### **5.1 == 运算符的行为** | **比较类型** | **== 的作用** | **示例** | | --- | --- | --- | | 基本类型 | 比较**值** | `5 == 5` → true | | 引用类型 | 比较**地址** | `s1 == s2` → 是否同一对象 | ``` // 基本类型用 == 比较值 int a = 100; int b = 100; System.out.println(a == b); // true(值相等) // 引用类型用 == 比较地址 String str1 = new String("Java"); String str2 = new String("Java"); System.out.println(str1 == str2); // false(不同对象) ``` ### **5.2 equals() 方法的行为** #### **Object 类的默认实现(源码)** ```java // java.lang.Object 类中的 equals 方法 public boolean equals(Object obj) { return (this == obj); // 默认比较引用! } ``` > *⚠️ **默认行为与 == 完全相同!** 需要子类重写才能比较内容。* #### **String 类的重写实现(源码解析)** ```java // java.lang.String 类中的 equals 方法 public boolean equals(Object anObject) { // 1️⃣ 先比较引用,相同直接返回 true if (this == anObject) { return true; } // 2️⃣ 检查类型是否是 String if (anObject instanceof String) { String anotherString = (String) anObject; int n = value.length; // 3️⃣ 比较长度 if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; // 4️⃣ 逐字符比较 while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } ``` **流程**图: ```drawio ``` ### **5.3 自定义类重写 equals()** ```java public class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object obj) { // 1. 引用相同 if (this == obj) return true; // 2. null 检查 + 类型检查 if (obj == null || getClass() != obj.getClass()) return false; // 3. 强制类型转换 Student student = (Student) obj; // 4. 比较各属性 return age == student.age && Objects.equals(name, student.name); } // 重写 equals 必须重写 hashCode(后续笔记详解) @Override public int hashCode() { return Objects.hash(name, age); } } ``` ### **5.4 == vs equals() 对比总结表** | **比较方式** | **基本类型** | **引用类型(未重写)** | **引用类型(已重写)** | | --- | --- | --- | --- | | `==` | 比较值 | 比较地址 | 比较地址 | | `equals()` | ❌ 不适用 | 比较地址(同==) | 比较内容 | --- ## **六、字符串的特殊情况** ### **6.1 字符串常量池** ```drawio ``` ### **6.2 代码验证** ```java public class StringPoolDemo { public static void main(String[] args) { // 字面量创建(使用常量池) String str1 = "Java"; String str2 = "Java"; // new 创建(强制新对象) String str3 = new String("Java"); String str4 = new String("Java"); // ====== == 比较(地址)====== System.out.println("str1 == str2: " + (str1 == str2)); // true ✅ 常量池复用 System.out.println("str1 == str3: " + (str1 == str3)); // false ❌ 不同对象 System.out.println("str3 == str4: " + (str3 == str4)); // false ❌ 不同对象 // ====== equals 比较(内容)====== System.out.println("str1.equals(str3): " + str1.equals(str3)); // true ✅ System.out.println("str3.equals(str4): " + str3.equals(str4)); // true ✅ // ====== intern() 方法 ====== String str5 = str3.intern(); // 返回常量池中的引用 System.out.println("str1 == str5: " + (str1 == str5)); // true ✅ } } ``` **输出结**果: ``` str1 == str2: true str1 == str3: false str3 == str4: false str1.equals(str3): true str3.equals(str4): true str1 == str5: true ``` ### **6.3 字符串创建方式对比** | **创建方式** | **代码示例** | **使用常量池** | **内存位置** | | --- | --- | --- | --- | | 字面量 | `"Java"` | ✅ 是 | 常量池 | | new | `new String("Java")` | ❌ 否 | 堆内存 | | intern() | `str.intern()` | ✅ 是 | 返回常量池引用 | | 拼接(常量) | `"Ja" + "va"` | ✅ 是 | 编译期优化 | | 拼接(变量) | `str + "va"` | ❌ 否 | 运行时新建 | --- ## **七、Integer 缓存池** ### **7.1 缓存池机制** ```java public class IntegerCacheDemo { public static void main(String[] args) { // -128 ~ 127 范围内使用缓存 Integer a = 100; Integer b = 100; System.out.println(a == b); // true ✅ 使用缓存 // 超出范围,创建新对象 Integer c = 200; Integer d = 200; System.out.println(c == d); // false ❌ 不同对象 // equals 比较内容 System.out.println(c.equals(d)); // true ✅ } } ``` ### **7.2 Integer.valueOf() 源码** ```java // java.lang.Integer 类 public static Integer valueOf(int i) { // 如果在缓存范围内,返回缓存对象 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; // 否则创建新对象 return new Integer(i); } // 缓存池内部类 private static class IntegerCache { static final int low = -128; static final int high = 127; // 可通过 JVM 参数调整 static final Integer cache[]; static { // 初始化缓存数组 cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } } ``` **流程图**: ```drawio ``` ### **7.3 各包装类缓存范围** | **包装类** | **缓存范围** | **说明** | | --- | --- | --- | | Byte | -128 ~ 127 | 全部缓存 | | Short | -128 ~ 127 | | | Integer | -128 ~ 127 | high 可通过 JVM 参数调整 | | Long | -128 ~ 127 | | | Character | 0 ~ 127 | | | Boolean | TRUE / FALSE | 只有两个值 | | Float | ❌ 无缓存 | 浮点数范围太大 | | Double | ❌ 无缓存 | 浮点数范围太大 | --- ## **八、最佳实践总结** ### **8.1 比较规则速查表** | **场景** | **推荐方式** | **示例** | | --- | --- | --- | | 基本类型比较 | `==` | `int a == int b` | | 对象内容比较 | `equals()` | `str1.equals(str2)` | | 对象是否同一个 | `==` | `obj1 == obj2` | | null 安全比较 | `Objects.equals()` | `Objects.equals(a, b)` | --- ### **8.2 常见陷阱** ```java // ❌ 陷阱 1:用 == 比较字符串内容 String input = new String("admin"); if (input == "admin") { // false! // 永远不会执行 } // ✅ 正确写法 if (input.equals("admin")) { // 正确执行 } // ✅ 更安全的写法(避免 NullPointerException) if ("admin".equals(input)) { // 常量在前,避免 input 为 null 时报错 } ``` ``` // ❌ 陷阱 2:用 == 比较包装类 Integer a = 200; Integer b = 200; if (a == b) { // false!超出缓存范围 // 可能不会执行 } // ✅ 正确写法 if (a.equals(b)) { // 正确执行 } ``` ### **8.3 核心要点记忆图** ```drawio ```